Graviton3 を利用してコスパに優れる Redmine 環境を構築してみた

Graviton3 を利用してコスパに優れる Redmine 環境を構築してみた

Clock Icon2024.10.01

こんにちは。テクニカルサポートチームのShiinaです。

はじめに

プロジェクトのタスク管理や課題管理のツールとして Redmine を利用する場合があります。
新規プロジェクト立ち上げの機会にツールを調達したいといったこともよくありますよね。
今回はコスパが良い Arm ベースの AWS Graviton3 の EC2 インスタンスに Redmine を一から構築してみました。
構築手順とハマったポイントなどをご紹介します。

前提

プロジェクトメンバーやお客様とのタスク管理に利用することを想定しています。
コスト重視の構成を取るため、冗長化は行いませんので、必要に応じて検討ください。
Redmine では添付ファイルによりストーレージが逼迫しやすいため、将来の拡張性を考慮したストレージ設計を行います。
また、ドメイン取得済みであることを前提としています。

  • インフラ
    単一の EC2 インスタンスに Web サーバと DB を構築します。
    ALB と RDS は使用しません。

  • ストレージ
    ルートボリュームとデータボリュームを分離します。

  • 実行ユーザ
    Redmine アプリケーション実行用ユーザ名として「redmine」を使用します。

EC2 インスタンス

検証したインスタンス情報は次の通りです。

  • OS: Ubuntu Server 24.04 LTS 64 bit Arm
  • AMI: ami-007bc34ad4cc33773
  • インスタンスタイプ: m7g.medium
  • EBS ボリューム: ルート用途 20 GB、データ用途 40 GB

利用バージョン

利用したコンポーネントのバージョンは次の通りです。

  • Redmine: 5.1.3
  • Ruby: 3.1.2
  • MariaDB: 10.11.8
  • Bundler: 2.5.20

構築の流れ

はじめにデータ用途の EBS ボリュームのフォーマットおよびマウントの永続化を行います。
次に必要なパッケージをインストールした後、MariaDB のデータディレクトリの引越しを行います。
その後、Ruby、Bundler をインストールして Redmine のインストールおよびセットアップを進めて行きます。
最後に Let's Encrypt 証明書を発行して HTTPS 通信の設定を行います。

構築手順

EC2 インスタンス作成

インスタンスタイプ、AMI、VPC、サブネット、セキュリティグループなどを指定して EC2 インスタンスを作成および EBS ボリュームをアタッチします。
ElasticIP 取得の上、EC2 インスタンスに割り当てておきます。
セキュリティグループの設定では HTTP、HTTPS のインバウンド通信を許可しておきます。

Launch-an-instance-EC2-ap-northeast-1-09-30-2024_05_47_PM

EBS ボリュームのフォーマットとマウント

ディスクデバイス確認の上、データ用の EBS ボリュームを /data にマウントとします。

lsblk -f
sudo file -s /dev/nvme0n1
sudo mkfs -t xfs /dev/nvme0n1
sudo mkdir /data
sudo mount /dev/nvme0n1 /data

EBS ボリュームのマウントを永続化するように UUID を確認の上、fstab を修正します。

sudo blkid
sudo vi /etc/fstab
/etc/fstab
UUID=xxxxx-xxxx-xxxx-xxxx-xxxxx  /data  xfs  defaults,nofail  0  2
sudo umount /data
sudo mount -a

必要パッケージインストール

パッケージ情報の更新します。

sudo apt update
sudo apt upgrade

必要なパッケージ類をインストールします。

sudo apt install ruby ruby-dev build-essential libmariadb-dev imagemagick libmagickwand-dev git curl libssl-dev libreadline-dev zlib1g-dev autoconf bison libyaml-dev libncurses5-dev libffi-dev libgdbm-dev apache2 libapache2-mod-passenger mariadb-server mariadb-client

Ruby インストール

rbenv と ruby-build を clone します。

git clone https://github.com/rbenv/rbenv.git ~/.rbenv
git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build

Ruby をインストールします。

rbenv install 3.1.2
rbenv global 3.1.2

※5分〜10分程度時間を要しますのでしばらくお待ちください。

Bundler インストール

sudo gem install bundler

MariaDB のデータディレクトリ移動

MariaDB のデータディレクトリを /data へ移動します。

sudo systemctl stop mariadb.service
sudo mkdir /data/mysql_data
sudo chmod 755 /data/mysql_data
sudo chown mysql:mysql /data/mysql_data
sudo cp -rfp /var/lib/mysql/* /data/mysql_data/

移動先のデータディレクトリを参照するように conf を修正します。

sudo vi /etc/mysql/mariadb.conf.d/50-server.cnf
50-server.cnf
[mysqld]
datadir=/data/mysql_data
sudo systemctl start mariadb.service

Redmine 用データベースとユーザー作成

Redmine 用の MariaDB データベースとユーザーを作成します。

sudo mysql -u root -p

※Enter password とパスワードが求められますが、入力せずそのままエンターでログインできます。

CREATE DATABASE redmine CHARACTER SET utf8mb4;
CREATE USER 'redmine'@'localhost' IDENTIFIED BY 'YourPassword';
GRANT ALL PRIVILEGES ON redmine.* TO 'redmine'@'localhost';
FLUSH PRIVILEGES;

ついでに root のパスワードも変更しておきます。

USE mysql;
ALTER USER 'root'@'localhost' IDENTIFIED BY 'YourAdminPassword';
EXIT;

Redmine ダウンロード

Redmine をダウンロードして解凍します。

cd /data
sudo wget https://www.redmine.org/releases/redmine-5.1.3.tar.gz
sudo tar xzf redmine-5.1.3.tar.gz
sudo mv redmine-5.1.3 redmine

サンプルファイルをコピーしてデータベース接続用のコンフィグファイルを用意します。

cd /data/redmine/config
sudo cp database.yml.example database.yml
sudo vi database.yml
database.yml
production:
  adapter: mysql2
  database: redmine
  host: localhost
  username: redmine
  password: "YourPassword"
  # Use "utf8" instead of "utfmb4" for MySQL prior to 5.7.7
  encoding: utf8mb4
  variables:
    # Recommended `transaction_isolation` for MySQL to avoid concurrency issues is
    # `READ-COMMITTED`.
    # In case of MySQL lower than 8, the variable name is `tx_isolation`.
    # See https://www.redmine.org/projects/redmine/wiki/MySQL_configuration
    # transaction_isolation: "READ-COMMITTED"
      tx_isolation: "READ-COMMITTED"

    (中略)

Gem インストール

cd /data/redmine
sudo bundle install --without development test

セッション保存用秘密鍵生成

sudo bundle exec rake generate_secret_token

データベースのセットアップ

sudo RAILS_ENV=production bundle exec rake db:migrate

デフォルトデータ設定

sudo RAILS_ENV=production REDMINE_LANG=ja bundle exec rake redmine:load_default_data

redmine ユーザ設定

sudo useradd -r -s /usr/sbin/nologin redmine
sudo chown -R redmine:redmine /data/redmine

Passenger 設定

デフォルトユーザを「redmine」と指定します。

sudo vi  /etc/apache2/mods-available/passenger.conf
passenger.conf
<IfModule mod_passenger.c>
  PassengerRoot /usr/lib/ruby/vendor_ruby/phusion_passenger/locations.ini
  PassengerDefaultRuby /usr/bin/ruby
  PassengerDefaultUser redmine
</IfModule>

Apache 設定

sudo vi /etc/apache2/sites-available/redmine.conf
redmine.conf
<VirtualHost *:80>
    ServerName redmine.example.com
    DocumentRoot /data/redmine/public
    <Directory /data/redmine/public>
        AllowOverride all
        Options -MultiViews
        Require all granted
    </Directory>
</VirtualHost>

有効化を行い、設定反映のためにサービスのリスタートを行います。

sudo a2enmod passenger
sudo a2ensite redmine
sudo systemctl restart apache2

ホストゾーンへのレコード登録

ドメイン名URLにアクセスできるよう、ドメインを管理しているパブリックホストゾーンにレコード名を登録します。
EC2 インスタンスに割り当てた ElasticIPアドレスを A レコードとして登録します。

動作確認(HTTP)

設定したドメイン名を指定して HTTP アクセスします。

http://redmine.example.com/

問題なく設定ができていれば、ログイン画面が表示されるはずです。

初期管理者ユーザでログインします。
ID: admin
password: admin

Redmine-09-26-2024_05_14_PM

HTTPS 通信設定

証明書設定のため一度 apache を停止します。

sudo systemctl stop apache2

certbot をインストールして証明書と秘密鍵を発行します。

sudo apt install certbot
sudo certbot certonly --standalone -d redmine.example.com

メールアドレス入力後、規約に同意を行うための Yes を入力します。
成功するとドメイン名を含む下記のようなディレクトリに証明書と秘密鍵が生成されます。

  • /etc/letsencrypt/live/redmine.example.com/fullchain.pem
  • /etc/letsencrypt/live/redmine.example.com/privkey.pem

証明書と秘密鍵を指定します。
また、HTTP アクセスを HTTPS アクセスにリダイレクトします。

sudo vi /etc/apache2/sites-available/redmine.conf
redmine.conf
<VirtualHost *:443>
    ServerName redmine.example.com
    DocumentRoot /data/redmine/public
    <Directory /data/redmine/public>
        AllowOverride all
        Options -MultiViews
        Require all granted
    </Directory>
    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/redmine.example.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/redmine.example.com/privkey.pem
</VirtualHost>
<VirtualHost *:80>
    ServerName redmine.example.com
    Redirect permanent / https://redmine.example.com/
</VirtualHost>

有効化後、apache を起動します。

sudo a2enmod ssl
sudo systemctl start apache2

動作確認(HTTPS)

設定したドメイン名のURLを指定して HTTPS アクセスします。

https://redmine.example.com/

HTTPS でアクセスできることを確認します。
ブラウザから利用している証明書も確認できます。

スクリーンショット-2024-09-30-17-57-42-png-3258×2530--09-30-2024_06_00_PM

注意事項

Let's Encrypt 証明書の有効期限は 90 日のため、2ヶ月程度ごとに証明書の更新作業が必要です。

ハマったポイント

transaction_isolation エラー

  • 事象
    データベースセットアップ時に以下のエラーが発生。
sudo RAILS_ENV=production bundle exec rake db:migrate

Mysql2::Error: Unknown system variable 'transaction_isolation' (Mysql2::Error)
  • 原因
    database.yml ではデフォルトで transaction_isolation パラメータを使用しますが、
    利用している RDBMS バージョンによっては tx_isolation パラメータを利用する必要があります。

  • 対処
    利用した MariaDB バージョン(10.11.8)では、tx_isolation を利用するようにパラメータを修正して実行したところうまく行きました。

Redmine の設定画面にアクセスすると Internal error が発生

  • 事象
    プロジェクトやチケット起票など通常の操作は問題ないのですが、なぜか設定画面にアクセスすると Internal error が発生。

Redmine-500-error-09-30-2024_05_21_PM

  • 原因
    apache のエラーログにはパーミッション不足を示すエラーログが記録されていました。
/var/log/apache2/error.log
Permission denied @ dir_s_mkdir - /opt/redmine/tmp/cache/D3B) 

Ruby アプリケーションの実行ユーザが nobody になっていたのが原因でした。

ps -ef | grep redmine

nobody     1261     678  1 07:50 ?        00:00:03 Passenger AppPreloader: /data/redmine
nobody    1302    1261  0 07:50 ?        00:00:00 Passenger RubyApp: /data/redmine (production)
  • 対処
    passenger.conf にて PassengerDefaultUser パラメータで実行ユーザ名(redmine)を指定したところ、解消。
passenger.conf
<IfModule mod_passenger.c>
  PassengerRoot /usr/lib/ruby/vendor_ruby/phusion_passenger/locations.ini
  PassengerDefaultRuby /usr/bin/ruby
  PassengerDefaultUser redmine
</IfModule>
ps -ef | grep redmine

redmine   1261     678  1 07:50 ?        00:00:03 Passenger AppPreloader: /data/redmine
redmine   1302    1261  0 07:50 ?        00:00:00 Passenger RubyApp: /data/redmine (production)

証明書発行に失敗する

  • 事象
    証明書発行時に以下のエラーが発生。
sudo certbot certonly --standalone -d redmine.example.com

Certbot failed to authenticate some domains (authenticator: standalone). The Certificate Authority reported these problems:
  Domain: redmine.example.com
  Type:   connection
  Detail: xxx.xxx.xxx.xxx: Fetching http://redmine.example.com/.well-known/acme-challenge/9mWilMxK1RQINk8BfocHy5M8JkUWyPfrB15BfHO22ws: Timeout duringconnect (likely firewall problem)

Hint: The Certificate Authority failed to download the challenge files from the temporary standalone webserver started by Certbot on port 80. Ensure that the listed domains point to this machine and that it can accept inbound connections from the internet.

  • 原因
    Let's Encrypt で証明書を発行する際に、特定ファイルに対して HTTP アクセスを行い、ドメイン所有者の確認が行われます。
    インバウンド通信を特定 IP アドレスからのみ許可するような設定をセキュリティグループで行なっていたことが原因でした。

  • 対処
    セキュリティグループで HTTP アクセスのインバウンド許可を実施したところ、無事に証明書が発行できました。

VirtualHost 設定後に apache サービス起動失敗

  • 事象
    VirtualHost で SSLEngine 有効化と証明書の秘密鍵のパスを指定した後、 apache サービスを起動を実施したところ、起動に失敗。
systemctl start apache2

Job for apache2.service failed because the control process exited with error code.
See "systemctl status apache2.service" and "journalctl -xeu apache2.service" for details.

systemctl status apache2.service

× apache2.service - The Apache HTTP Server
     Loaded: loaded (/usr/lib/systemd/system/apache2.service; enabled; preset: enabled)
     Active: failed (Result: exit-code) since Fri 2024-09-27 01:21:29 UTC; 21s ago
   Duration: 37min 50.177s
       Docs: https://httpd.apache.org/docs/2.4/
    Process: 2763 ExecStart=/usr/sbin/apachectl start (code=exited, status=1/FAILURE)
        CPU: 11ms

Sep 27 01:21:29 ip-10-0-0-233 systemd[1]: Starting apache2.service - The Apache HTTP Server...
Sep 27 01:21:29 ip-10-0-0-233 apachectl[2765]: AH00526: Syntax error on line 9 of /etc/apache2/sites-enabled/redmine.conf:
Sep 27 01:21:29 ip-10-0-0-233 apachectl[2765]: Invalid command 'SSLEngine', perhaps misspelled or defined by a module not included in the server configuration
Sep 27 01:21:29 ip-10-0-0-233 systemd[1]: apache2.service: Control process exited, code=exited, status=1/FAILURE
Sep 27 01:21:29 ip-10-0-0-233 systemd[1]: apache2.service: Failed with result 'exit-code'.
Sep 27 01:21:29 ip-10-0-0-233 systemd[1]: Failed to start apache2.service - The Apache HTTP Server.
  • 原因
    SSL モジュールが有効化されいなかったことが原因でした。
    SSLEngine を利用する場合はモジュールの有効化が必要です。

  • 対象
    a2enmod コマンドで ssl を有効化したところ、起動できるようになりました。

sudo a2enmod ssl

プラグイン動作確認

プラグインの動作も確認してみました。
試しにダークモードに変更するプラグインを導入してみましたが、問題なく動作しました。

cd /data/redmine/plugins
sudo -u redmine git clone https://github.com/fraoustin/redmine_dark
sudo systemctl restart apache2

バグ-1-テストチケット-サンプルプロジェクト-Redmine-09-26-2024_05_14_PM

まとめ

特別な考慮や手順など不要で Graviton3 の EC2 インスタンスでも Redmine を導入することができました。
構築を検討されてる方は Graviton3 を利用してコスパよく利用してみてはいかがでしょうか。
Let's Encrypt の証明書は有効期限が短いため、管理面がすこし煩わしいです。
コストは増えますが、ALB を利用する構成とすれば、ACM で発行した証明書を利用できるため、証明書の管理自体をなくこともできます。

本記事が誰かのお役に立てれば幸いです。

参考

https://redmine.jp/guide/RedmineInstall/#step-1-redmine
https://eff-certbot.readthedocs.io/en/latest/using.html#manual
https://github.com/fraoustin/redmine_dark

この記事をシェアする

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.